home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Games / Xconq 7.0d16 / Xconq 7.0d16 src / mac / macconq.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-16  |  42.5 KB  |  1,777 lines  |  [TEXT/KAHL]

  1. /* Copyright (c) 1992, 1993  Stanley T. Shebs. */
  2. /* This program may be used, copied, modified, and redistributed freely */
  3. /* for noncommercial purposes, so long as this notice remains intact. */
  4.  
  5. /* Main Mac interface. */
  6.  
  7. #include "conq.h"
  8. #include "mac.h"
  9.  
  10. extern int beforestart, endofgame;
  11.  
  12. #include <GestaltEqu.h>
  13. #include <PPCToolbox.h>
  14. #include <AppleEvents.h>
  15.  
  16. #include <time.h>
  17.  
  18. /* The console is a useful debugging hack.  When not in use, anything that uses stdout
  19.    should be disabled. */
  20.  
  21. #ifdef USE_CONSOLE
  22. #ifdef THINK_C
  23. #include <console.h>
  24. #include <Folders.h>
  25. #else
  26. #ifndef printf
  27. printf() {}
  28. #endif
  29. #endif
  30. #endif
  31.  
  32. /* (from DTS sample code) */
  33. /* kOSEvent is the event number of the suspend/resume and mouse-moved events sent
  34.    by MultiFinder. Once we determine that an event is an osEvent, we look at the
  35.    high byte of the message sent to determine which kind it is. To differentiate
  36.    suspend and resume events we check the resumeMask bit. */
  37.  
  38. #define    kOSEvent                app4Evt
  39.  
  40. /* high byte of suspend/resume event message */
  41.  
  42. #define    kSuspendResumeMessage    1
  43.  
  44. /* bit of message field for resume vs. suspend */
  45.  
  46. #define    kResumeMask                1
  47.  
  48. /* high byte of mouse-moved event message */
  49.  
  50. #define    kMouseMovedMessage        0xFA
  51.  
  52. #define keyReplyErr        'errn'
  53.  
  54. /* This is the id of any modal tool currently in effect. */
  55.  
  56. int modaltool = 0;
  57.  
  58. int inbackground;
  59.  
  60. /* This is the list of maps that we're using. */
  61.  
  62. struct a_map *maplist;
  63.  
  64. /* This is the list of lists. */
  65.  
  66. struct a_list *listlist;
  67.  
  68. /* This is the list of unit closeups. */
  69.  
  70. struct a_unit_closeup *unitcloseuplist;
  71.  
  72. struct a_side_closeup *sidecloseuplist;     /* chain of side closeups */
  73.  
  74. int foundresourcesfile = FALSE;
  75.  
  76. /* This flag indicates whether the image etc resource file(s) were found. */
  77.  
  78. int foundimagesfile = FALSE;
  79.  
  80. /* The usual width of a scrollbar. */
  81.  
  82. int sbarwid = 15;
  83.  
  84. int defaultdrawgrid = TRUE;           /* Display grid on the map? */
  85. int defaultdrawnames = FALSE;           /* Display unit names/numbers on the map? */
  86.  
  87. /* True if we're going to use WaitNextEvent. */
  88.  
  89. int useWNE = FALSE;
  90.  
  91. /* Rectangle that constrains window dragging. */
  92.  
  93. Rect dragrect;
  94.  
  95. /* Rectangle that constrains window resizing. */
  96.  
  97. Rect sizerect;
  98.  
  99. /* This is the side that is using this Mac as its display. */
  100.  
  101. Side *dside = NULL;
  102.  
  103. /* This points to a spare block of memory that is freed so shutdown code can
  104.    use it (no guarantee that it will tho). */
  105.  
  106. Handle spare;
  107.  
  108. /* This is true if savable prefs etc have been saved since being changed. */
  109. /* (always true for now, nothing being remembered) */
  110.  
  111. int interfacestatesafe = TRUE;
  112.  
  113. /* This is true when a single click suffices to move a unit. */
  114.  
  115. int defaultmoveonclick = TRUE;
  116.  
  117. int defaultautoselect = TRUE;
  118.  
  119. int wasingame = TRUE;
  120.  
  121. int suppresswarnings = FALSE;
  122.  
  123. int playsounds = TRUE;
  124.  
  125. /* Set to true if Color QuickDraw is installed. */
  126.  
  127. int hasColorQD;
  128.  
  129. /* The range of screen pixel depths that the display has to cope with. */
  130.  
  131. int minscreendepth = -1;
  132.  
  133. int maxscreendepth = -1;
  134.  
  135. /* This is true if AppleEvents are available. */
  136.  
  137. int hasAppleEvents;
  138.  
  139. /* This is true if the PPC toolbox is available. */
  140.  
  141. int hasPPCToolbox;
  142.  
  143. time_t realstarttime;
  144.  
  145. /* The HFS volume that the program started with. */
  146.  
  147. short initialvrefnum;
  148.  
  149. char *curdatestr = NULL;
  150.  
  151. int eventloopdone = FALSE;
  152.  
  153. int inputinvalid = FALSE;
  154.  
  155. /* The main Mac program. */
  156.  
  157. main()
  158. {
  159.     /* Do the most basic Macintosh setup. */
  160.     init_toolbox();
  161.     init_cursors();
  162.     init_menus();
  163.     init_rects();
  164.     init_ae();
  165. #ifdef USE_CONSOLE
  166.     /* Make sure the console window is up before anybody tries to write to it. */
  167.     freopenc(NULL, stdout);
  168.     freopenc(stdout, stderr);
  169. #endif
  170.     /* Acquire Mac-specific files (preferences and resources). */
  171.     get_files();
  172.     /* Put the Xconq kernel into a known state. */
  173.     clear_game_modules();
  174.     init_data_structures();
  175.     init_library_path();
  176.     /* A hack to ensure some memory available for error handling. */
  177.     spare = NewHandle(2000);
  178.     /* If no Apple Events, go to the splash screen now, otherwise we'll wait
  179.        for an oapp/odoc/pdoc event to decide what to do. */
  180.     if (!hasAppleEvents) {
  181.         if (splash_dialog() == diSplashQuit) return;
  182.     }
  183.     /* All essential init done, jump into the main event loop. */
  184.     event_loop();
  185. }
  186.  
  187. splash_dialog()
  188. {
  189.     switch (do_splash_box()) {
  190.         case diSplashNew:
  191.             new_game_dialog();
  192.             break;
  193.         case diSplashOpen:
  194.             open_game_dialog();
  195.             break;
  196.         case diSplashConnect:
  197.             connect_game_dialog();
  198.             break;
  199.         case diSplashQuit:
  200.             return diSplashQuit;
  201.     }
  202.     return -1;
  203. }
  204.  
  205. /* (just a place holder for now) */
  206.  
  207. connect_game_dialog()
  208. {
  209.     LocationNameRec foo;
  210.     PortInfoRec bar;
  211.     
  212.     PPCBrowser("\pEventually you'll be able to choose an Xconq game from here!",
  213.                "\pXconq", 0, &foo, &bar, NULL, "\p?");
  214. }
  215.  
  216. /* Do the usual Mac setup calls. */
  217.  
  218. init_toolbox()
  219. {
  220.     SysEnvRec se;
  221.  
  222.     InitGraf(&QD(thePort));
  223.     InitFonts();
  224.     FlushEvents(everyEvent, 0);
  225.     InitWindows();
  226.     InitMenus();
  227.     TEInit();
  228.     InitDialogs(NULL);
  229.     InitCursor();
  230.  
  231.     SysEnvirons(2, &se);
  232.     hasColorQD = se.hasColorQD;
  233.     DGprintf("%s Color QuickDraw\n", (hasColorQD ? "Using" : "Not using"));
  234.     recalc_depths();
  235. }
  236.  
  237. recalc_depths()
  238. {
  239.     int depth, oldmin = minscreendepth, oldmax = maxscreendepth;
  240.     GDHandle gdev;
  241.  
  242.     if (hasColorQD) {
  243.         gdev = GetDeviceList();
  244.         minscreendepth = maxscreendepth = (*((*gdev)->gdPMap))->pixelSize;
  245.         while ((gdev = GetNextDevice(gdev)) != nil) {
  246.             depth = (*((*gdev)->gdPMap))->pixelSize;
  247.             if (depth < minscreendepth) minscreendepth = depth;
  248.             if (depth > maxscreendepth) maxscreendepth = depth;
  249.         }
  250.     } else {
  251.         minscreendepth = maxscreendepth = 1;
  252.     }
  253.     if (minscreendepth != oldmin || maxscreendepth != oldmax) {
  254.         DGprintf("Screen depths range from %d to %d\n", minscreendepth, maxscreendepth);
  255.     }
  256. }
  257.  
  258. /* Set up the generic dragging and sizing rects. */
  259.  
  260. init_rects()
  261. {
  262.     RgnHandle screenrgn;
  263.  
  264.     screenrgn = GetGrayRgn();
  265.     dragrect = (*screenrgn)->rgnBBox;
  266.     SetRect(&sizerect, 50, 50, (*screenrgn)->rgnBBox.right,  (*screenrgn)->rgnBBox.bottom);
  267. }
  268.  
  269. pascal OSErr do_ae_open_application(AppleEvent *message, AppleEvent *reply, long refcon);
  270. pascal OSErr do_ae_open_documents(AppleEvent *message, AppleEvent *reply, long refcon);
  271. pascal OSErr do_ae_print_documents(AppleEvent *message, AppleEvent *reply, long refcon);
  272. pascal OSErr do_ae_quit_application(AppleEvent *message, AppleEvent *reply, long refcon);
  273.  
  274. typedef struct triplets{
  275.     AEEventClass    theEventClass;
  276.     AEEventID        theEventID;
  277.     ProcPtr            theHandler;
  278. } triplets;
  279.  
  280. triplets keywordsToInstall[] = {
  281.     { kCoreEventClass, kAEOpenApplication, (ProcPtr) do_ae_open_application },
  282.     { kCoreEventClass, kAEOpenDocuments, (ProcPtr) do_ae_open_documents },
  283.     { kCoreEventClass, kAEPrintDocuments, (ProcPtr) do_ae_print_documents },
  284.     { kCoreEventClass, kAEQuitApplication, (ProcPtr) do_ae_quit_application }
  285. };
  286.  
  287. init_ae()
  288. {
  289.     OSErr    err;
  290.     long    result;
  291.     short    i;
  292.  
  293.     /* (should check that we have Gestalt first) */
  294.     hasPPCToolbox  = (Gestalt(gestaltPPCToolboxAttr, &result) ? false : result != 0);
  295.     hasAppleEvents = (Gestalt(gestaltAppleEventsAttr, &result) ? false : result != 0);
  296.  
  297.     if (hasAppleEvents) {
  298.         for (i = 0; i < (sizeof(keywordsToInstall) / sizeof(triplets)); ++i) {
  299.             err = AEInstallEventHandler(
  300.                 keywordsToInstall[i].theEventClass,    /* What class to install.  */
  301.                 keywordsToInstall[i].theEventID,    /* Keywords to install.    */
  302.                 keywordsToInstall[i].theHandler,    /* The AppleEvent handler. */
  303.                 0L,                                    /* Unused refcon.           */
  304.                 false                                /* Only for our app.       */
  305.             );
  306.  
  307.             if (err) {
  308. /*                Alert(rErrorAlert, nil);  */
  309.                 SysBeep(20);
  310.                 return;
  311.             }
  312.         }
  313.     }
  314. }
  315.  
  316. /* Open and/or load any files that we might need, such as preferences
  317.    and resources. */
  318.  
  319. get_files()
  320. {
  321.     short vref, refnum;
  322.     long dirid;
  323.     Str255 filename;
  324.     FSSpec spec;
  325.  
  326.     /* Capture the current vrefnum. */
  327.     GetVol(NULL, &initialvrefnum);
  328.     /* Load up any preferences. */
  329.     GetIndString(filename, sFilenames, siPreferences);
  330. #ifndef THINK_C
  331.     if (FindFolder(kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder,
  332.                    &vref, &dirid) == noErr) {
  333.         if (FSMakeFSSpec(vref, dirid, filename, &spec) == noErr) {
  334.             refnum = FSpOpenResFile(&spec, fsCurPerm);
  335.             CloseResFile(refnum);
  336.         }
  337.     }
  338. #endif
  339.     /* Look for and open game library resource file(s). */
  340.     foundresourcesfile = FALSE;
  341.     GetIndString(filename, sFilenames, siResources);
  342.     if (OpenResFile(filename) != -1) {
  343.         foundresourcesfile = TRUE;
  344.     }
  345.     foundimagesfile = FALSE;
  346.     GetIndString(filename, sFilenames, siImages);
  347.     if (OpenResFile(filename) != -1) {
  348.         foundimagesfile = TRUE;
  349.     }
  350.     /* Note that we don't complain yet if the resource/image files are missing,
  351.        since we don't yet know whether we actually need anything from them.
  352.        (Images etc might be built into app or game module, for instance.) */
  353. }
  354.  
  355. /* Since Mac programs effectively take over the entire machine, we depend on
  356.    this event loop to handle everything that might come along.  */
  357.  
  358. event_loop()
  359. {
  360.     int done = FALSE;
  361.     Boolean gotevent;
  362.     Point mouse;
  363.     EventRecord    event;
  364.     WindowPtr win;
  365.     RgnHandle cursorRgn;
  366.  
  367.     /* Figure out if the WaitNextEvent Trap is available. */
  368.     useWNE = (NGetTrapAddress(0x60, ToolTrap) != NGetTrapAddress(0x9f, ToolTrap));
  369.     /* Pass WNE an empty region the 1st time thru. */
  370.     cursorRgn = NewRgn();
  371.     /* Loop (almost) forever. */
  372.     while (!eventloopdone) {
  373.         /* Use WaitNextEvent if it is available, otherwise GetNextEvent. */
  374.         if (useWNE) {
  375.             get_global_mouse(&mouse);
  376.             adjust_cursor(mouse, cursorRgn);
  377.             gotevent = WaitNextEvent(everyEvent, &event, 0L, cursorRgn);
  378.         } else {
  379.             SystemTask();
  380.             gotevent = GetNextEvent(everyEvent, &event);
  381.         }
  382.         /* First decide if the event is for a dialog or is just any old event. */
  383.         if (FrontWindow() != nil && IsDialogEvent(&event)) {
  384.             short itemhit;
  385.             DialogPtr dialog;
  386.  
  387.             /* Handle all the modeless dialogs here. */
  388.             if (DialogSelect(&event, &dialog, &itemhit)) {
  389.                 if (dialog == instructionswin) {
  390.                     hit_instructions_dialog(dialog, itemhit, &event);
  391.                 /* } else if (dialog == helpwin) {
  392.                     hit_help_dialog(dialog, itemhit, &event); */
  393.                 } else if (dside != NULL) {
  394.                     if (hit_in_side_closeup(dialog, itemhit, &event)) {
  395.                     } else {
  396.                         DGprintf("random dialog hit?\n");
  397.                     }
  398.                 } else {
  399.                     DGprintf("really random dialog hit?\n");
  400.                 }
  401.             } else {
  402.                 /* ??? */
  403.             }
  404.         } else if (gotevent) {
  405.             /* Make sure we have the right cursor before handling the event. */
  406.             adjust_cursor(event.where, cursorRgn);
  407.             do_event(&event);
  408.         } else if (!beforestart && !endofgame) {
  409.             /* On null events, give the kernel a chance to run things. */
  410.             /* Don't automatically go to a watch cursor, since run_game often
  411.                returns very quickly.  Instead, long-running subroutines should
  412.                call back to put a watch cursor up. */
  413.             run_game(1);
  414.             maybe_select_next_unit();
  415.             /* If the game ended, force various changes in interaction. */
  416.             if (endofgame) {
  417.                 Map *map;
  418.  
  419.                 for_all_maps(map) {
  420.                     map->moveonclick = map->autoselect = FALSE;
  421.                 }
  422.             }
  423.         }
  424.     }
  425. }
  426.  
  427. get_global_mouse(mouse)
  428. Point *mouse;
  429. {
  430.     EventRecord    evt;
  431.     
  432.     OSEventAvail(0, &evt);
  433.     *mouse = evt.where;
  434. }
  435.  
  436. Point lastmouse;
  437.  
  438. char mouseoverbuf[100];
  439.  
  440. /* Change the cursor to reflect the context. */
  441.  
  442. adjust_cursor(mouse, region)
  443. Point mouse;
  444. RgnHandle region;
  445. {
  446.     int x, y, approxdir = 1, usual = TRUE;
  447.     Unit *unit = NULL;
  448.     extern char *mouseover;
  449.     extern int beforestart, endofgame;
  450.     Map *map;
  451.     CursPtr adjust_designer_cursor();
  452.     GrafPtr oldport;
  453.     extern CursHandle firecursor;
  454.  
  455.     if ((map = map_from_window(FrontWindow())) != NULL) {
  456.         GetPort(&oldport);
  457.         SetPort(map->window);
  458.         GlobalToLocal(&mouse);
  459.         if (PtInRect(mouse, &(map->contentrect))) {
  460.             if (modaltool > 0) {
  461.                 switch (modaltool) {
  462.                     case 1:
  463.                         SetCursor(*opencrosscursor);
  464.                         break;
  465.                     case 2:
  466.                         SetCursor(*firecursor);
  467.                         break;
  468.                     default:
  469.                         /* (should error out here) */
  470.                         break;
  471.                 }
  472.                 usual = FALSE;
  473. #ifdef DESIGNERS
  474.             } else if (dside->designer && tooltype != notool) {
  475.                 SetCursor(adjust_designer_cursor(mouse, region));  usual = FALSE;
  476. #endif DESIGNERS
  477.             } else if (map->moveonclick) {
  478.                 if (map->numselections == 1
  479.                     && (unit = map->selections[0]) != NULL) {
  480.                     /* Calculate the approx dir to here from selected unit. */
  481.                     nearest_cell(map, mouse.h, mouse.v, &x, &y);
  482.                     if (mobile(unit->type)
  483.                         && (approxdir = approx_dir(x - unit->x, y - unit->y)) >= 0) {
  484.                         SetCursor(*(movecursors[approxdir]));  usual = FALSE;
  485.                     } else {
  486.                         SetCursor(*nomovecursor);  usual = FALSE;
  487.                     }
  488.                 } else if (map->numselections > 1) {
  489.                     SetCursor(*allmovecursor);  usual = FALSE;
  490.                 } else {
  491.                     /* (this is a little confusing here if no units are selected, since
  492.                        will just be arrow cursor) */
  493.                 }
  494.             }
  495.             /* This isn't really "cursor adjustment", but this is the right place
  496.                to do it - change the topline of the map to indicate what the cursor
  497.                is over. */
  498.             if (map->toph > 0 && !EqualPt(mouse, lastmouse)) {
  499.                 oneliner(map, mouse.h, mouse.v);
  500.                 if (strcmp(tmpbuf, mouseoverbuf) != 0) {
  501.                     strcpy(mouseoverbuf, tmpbuf);
  502.                     mouseover = mouseoverbuf;
  503.                     draw_top_line(map);
  504.                 }
  505.                 lastmouse = mouse;
  506.             }
  507.         } else {
  508.             if (map->toph > 0) {
  509.                 if (mouseover != NULL) {
  510.                     mouseover = NULL;
  511.                     draw_top_line(map);
  512.                 }
  513.             }
  514.         }
  515.         SetPort(oldport);
  516.     }
  517.     
  518.     if (endofgame || (!beforestart && dside && !dside->ingame)) {
  519.         SetCursor(*grayarrowcursor);
  520.         return;
  521.     }
  522.     /* If we got here and no cursor has been set already, go with the basic arrow. */
  523.     if (usual) SetCursor(&QD(arrow));
  524. }
  525.  
  526. /* Decipher an event. */
  527.  
  528. do_event(event)
  529. EventRecord *event;
  530. {
  531.     short part, err, rslt = 0;
  532.     WindowPtr win;
  533.     Boolean hit;
  534.     char key;
  535.     Point pnt;
  536.     GrafPtr oldport;
  537.  
  538.     switch (event->what) {
  539.         case mouseDown:
  540.             /* See if the click happened in a special part of the screen. */
  541.             part = FindWindow(event->where, &win);
  542.             switch (part) {
  543.                 case inMenuBar:
  544.                     adjust_menus();
  545.                     do_menu_command(MenuSelect(event->where));
  546.                     break;
  547.                 case inSysWindow:
  548.                     SystemClick(event, win);
  549.                     break;
  550.                 case inContent:
  551.                     if (win != FrontWindow()) {
  552.                         /* Bring the clicked-on window to the front. */
  553.                         SelectWindow(win);
  554.                         /* Fix the menu to match the new front window. */
  555.                         adjust_menus();
  556.                         /* We always want to discard the event now, since clicks in a
  557.                            windows are often irreversible actions. */
  558.                     } else {
  559.                         /* Mouse clicks in the front window do something useful. */
  560.                         do_mouse_down(win, event);
  561.                     }
  562.                     break;
  563.                 case inDrag:
  564.                     /* Standard drag behavior, no tricks necessary. */
  565.                     DragWindow(win, event->where, &dragrect);
  566.                     break;
  567.                 case inGrow:
  568.                     grow_window(win, event->where);
  569.                     break;
  570.                 case inZoomIn:
  571.                 case inZoomOut:
  572.                     zoom_window(win, event->where, part);
  573.                     break;
  574.                 case inGoAway:
  575.                     close_window(win);
  576.                     break;
  577.             }
  578.             break;
  579.         case keyDown:
  580.         case autoKey:
  581.             key = event->message & charCodeMask;
  582.             /* Check for menukey equivalents. */
  583.             if (event->modifiers & cmdKey) {
  584.                 if (event->what == keyDown) {
  585.                     adjust_menus();
  586.                     do_menu_command(MenuKey(key));
  587.                 }
  588.             } else {
  589.                 if (event->what == keyDown) {
  590.                     /* Random keypress, interpret it. */
  591.                     do_keyboard_command(key);
  592.                 }
  593.             }
  594.             break;
  595.         case activateEvt:
  596.             activate_window((WindowPtr) event->message, event->modifiers & activeFlag);
  597.             break;
  598.         case updateEvt:
  599.             update_window((WindowPtr) event->message);
  600.             break;
  601.         case diskEvt:
  602.             /*    Call DIBadMount in response to a diskEvt, so that the user can format
  603.                  a floppy. (from DTS Sample) */
  604.             if (HiWord(event->message) != noErr) {
  605.                 SetPt(&pnt, 50, 50);
  606.                 err = DIBadMount(pnt, event->message);
  607.             }
  608.             break;
  609.         case kOSEvent:
  610.             /* Grab only a single byte. */
  611.             switch ((event->message >> 24) & 0x0FF) {
  612.                 case kMouseMovedMessage:
  613.                     break;
  614.                 case kSuspendResumeMessage:
  615.                     inbackground = !(event->message & kResumeMask);
  616.                     activate_window(FrontWindow(), !inbackground);
  617.                     break;
  618.             }
  619.             break;
  620. #ifdef THINK_C
  621.         case kHighLevelEvent:
  622.             AEProcessAppleEvent(event);
  623.             break;
  624. #endif
  625.         case nullEvent:
  626.             rslt = 1;
  627.             break;
  628.         default:
  629.             break;
  630.     }
  631. #ifdef DEBUGGING
  632.     /* This just forces output into the file. */
  633.     update_debugging();
  634. #endif
  635.     return rslt;
  636. }
  637.  
  638. /* Handle window growing by mindlessly tracking via GrowWindow,
  639.    then passing the chosen size to specific window resize handlers
  640.    or else doing the generic resize. */
  641.  
  642. grow_window(win, where)
  643. WindowPtr win;
  644. Point where;
  645. {
  646.     long winsize;
  647.     short winh, winv;
  648.     GrafPtr oldport;
  649.  
  650.     if ((winsize = GrowWindow(win, where, &sizerect)) != 0) {
  651.         GetPort(&oldport);
  652.         SetPort(win);
  653.         winh = LoWord(winsize);  winv = HiWord(winsize);
  654.         if (map_from_window(win)) {
  655.             grow_map(map_from_window(win), winh, winv);
  656.         } else if (list_from_window(win)) {
  657.             grow_list(list_from_window(win), winh, winv);
  658.         } else if (win == historywin) {
  659.             grow_history(winh, winv);
  660.         } else if (win == constructionwin) {
  661.             grow_construction(winh, winv);
  662.         } else if (win == helpwin) {
  663.             grow_help(winh, winv);
  664.         }
  665.         SetPort(oldport);
  666.     }
  667. }
  668.  
  669. zoom_window(win, where, part)
  670. WindowPtr win;
  671. Point where;
  672. short part;
  673. {
  674.     GrafPtr oldport;
  675.  
  676.     if (TrackBox(win, where, part)) {
  677.         GetPort(&oldport);
  678.         /* The window must be the current port. (ZoomWindow bug) */
  679.         SetPort(win);
  680.         if (map_from_window(win)) {
  681.             zoom_map(map_from_window(win), part);
  682.         } else if (list_from_window(win)) {
  683.             zoom_list(list_from_window(win), part);
  684.         } else if (win == historywin) {
  685.             zoom_history(part);
  686.         } else {
  687.             /* Generic window zooming. */
  688.             EraseRect(&win->portRect);
  689.             ZoomWindow(win, part, true);
  690.             InvalRect(&win->portRect);
  691.         }
  692.         SetPort(oldport);
  693.     }
  694. }
  695.  
  696. close_window(win)
  697. WindowPtr win;
  698. {
  699.     if (is_da_window(win)) {
  700.         CloseDeskAcc(((WindowPeek) win)->windowKind);
  701.     } else if (is_app_window(win)) {
  702.         /* Remove from the windows menu (OK to call even if window not in menu). */
  703.         remove_window_menu_item(win);
  704.         /* Do special activities for some window subtypes. */
  705.         if (map_from_window(win)) {
  706.             destroy_map(map_from_window(win));
  707.         } else if (list_from_window(win)) {
  708.             destroy_list(list_from_window(win));
  709.         } else if (unit_closeup_from_window(win)) {
  710.             destroy_unit_closeup(unit_closeup_from_window(win));
  711. #ifdef DESIGNERS
  712.         } else if (win == designwin) {
  713.             /* Closing the design palette implies we're done designing. */
  714.             disable_designing();
  715. #endif /* DESIGNERS */
  716.         }
  717.         /* Remove the window from our sight, will provoke update events. */
  718.         HideWindow(win);
  719.         /* At least for now, don't actually dispose of the window. */
  720.     }
  721. }
  722.  
  723. /* This just dispatches to the appropriate window handler. */
  724.  
  725. do_mouse_down(window, event)
  726. WindowPtr window;
  727. EventRecord *event;
  728. {
  729.     Point mouse;
  730.     Map *map;
  731.     List *list;
  732.     UnitCloseup *unitcloseup;
  733.  
  734.     if (is_app_window(window)) {
  735.         SetPort(window);
  736.         mouse = event->where;
  737.         GlobalToLocal(&mouse);
  738.         /* Locate the interface object that this is on. */
  739.         if ((map = map_from_window(window)) != NULL) {
  740.             do_mouse_down_map(map, mouse, event->modifiers); 
  741.         } else if ((list = list_from_window(window)) != NULL) {
  742.             do_mouse_down_list(list, mouse, event->modifiers); 
  743.         } else if ((unitcloseup = unit_closeup_from_window(window)) != NULL) {
  744.             do_mouse_down_unit_closeup(unitcloseup, mouse, event->modifiers); 
  745.         } else if (window == gamewin) {
  746.             do_mouse_down_game(mouse, event->modifiers);
  747.         } else if (window == historywin) {
  748.             do_mouse_down_history(mouse, event->modifiers);
  749.         } else if (window == constructionwin) {
  750.             do_mouse_down_construction(mouse, event->modifiers);
  751.         } else if (window == helpwin) {
  752.             do_mouse_down_help(mouse, event->modifiers);
  753. #ifdef DESIGNERS
  754.         } else if (window == designwin) {
  755.             do_mouse_down_design(mouse, event->modifiers);
  756. #endif /* DESIGNERS */
  757.         }
  758.     } else {
  759.         /* ??? */
  760.     }
  761. }
  762.  
  763. /* Bringing a window to the front may entail messing with the menu. */
  764.  
  765. activate_window(win, activate)
  766. WindowPtr win;
  767. int activate;
  768. {
  769.     Map *map;
  770.     List *list;
  771.  
  772.     if (win == nil) return;
  773.     if ((map = map_from_window(win)) != NULL) {
  774.         activate_map(map, activate);
  775.     } else if ((list = list_from_window(win)) != NULL) {
  776.         activate_list(list, activate);
  777.     } else if (win == constructionwin) {
  778.         activate_construction(activate);
  779.     } else if (win == helpwin) {
  780.         activate_help(activate);
  781.     } else {
  782.         DGprintf("%sactivating random window\n", (activate ? "" : "de"));
  783.     }
  784.     if (activate) {
  785.         /* It's convenient to make the activated window also be the current GrafPort. */
  786.         SetPort(win);
  787.     }
  788.     adjust_menus();
  789. }
  790.  
  791. /* Update a given window.  This is the main routine that causes drawing into
  792.    all the different kinds of windows. */
  793.  
  794. update_window(win)
  795. WindowPtr win;
  796. {
  797.     int controls = TRUE, growbox = FALSE;
  798.     GrafPtr oldport;
  799.     Map *map;
  800.     List *list;
  801.     SideCloseup *sidecloseup;
  802.     UnitCloseup *unitcloseup;
  803.  
  804.     /* Set the updating window to be the current grafport. */
  805.     GetPort(&oldport);
  806.     SetPort(win);
  807.     recalc_depths();
  808.     BeginUpdate(win);
  809.     if ((map = map_from_window(win)) != NULL) {
  810.         erase_map(map);
  811.         draw_map(map);
  812.         growbox = TRUE;
  813.     } else if ((list = list_from_window(win)) != NULL) {
  814.         draw_list(list);
  815.         growbox = TRUE;
  816.     } else if ((unitcloseup = unit_closeup_from_window(win)) != NULL) {
  817.         draw_unit_closeup(unitcloseup);
  818.     } else if ((sidecloseup = side_closeup_from_window(win)) != NULL) {
  819.         draw_side_closeup(sidecloseup);
  820.     } else if (win == gamewin) {
  821.         draw_game();
  822.         controls = FALSE;
  823.     } else if (win == historywin) {
  824.         draw_history();
  825.         growbox = TRUE;
  826.     } else if (win == constructionwin) {
  827.         draw_construction();
  828.         growbox = TRUE;
  829.     } else if (win == helpwin) {
  830.         draw_help();
  831.         growbox = TRUE;
  832. #ifdef DESIGNERS
  833.     } else if (win == designwin) {
  834.         draw_design_window();
  835.         controls = FALSE;
  836. #endif /* DESIGNERS */
  837.     } else {
  838.         controls = FALSE;
  839.     }
  840.     if (controls) {
  841.         UpdateControls(win, win->visRgn);
  842.     }
  843.     if (growbox) {
  844.         DrawGrowIcon(win);
  845.     }
  846.     EndUpdate(win);
  847.     SetPort(oldport);
  848. }
  849.  
  850. maybe_select_next_unit()
  851. {
  852.     Map *map;
  853.  
  854.     if ((!beforestart && !endofgame)
  855.         && (map = map_from_window(FrontWindow())) != NULL
  856.         && map->autoselect) {
  857.         map->curunit = autonext_unit(dside, map->curunit);
  858.         select_exactly_one_unit(map, map->curunit);
  859.     }
  860. }
  861.  
  862. /* Used to check for any unread required parameters. Returns true if we
  863.    missed at least one. */
  864.  
  865. Boolean
  866. MissedAnyParameters(AppleEvent *message)
  867. {
  868.     OSErr        err;
  869.     DescType    ignoredActualType;
  870.     AEKeyword    missedKeyword;
  871.     Size        ignoredActualSize;
  872.     EventRecord    event;
  873.  
  874.     err = AEGetAttributePtr(    /* SEE IF PARAMETERS ARE ALL USED UP.          */
  875.         message,                /* AppleEvent to check.                          */
  876.         keyMissedKeywordAttr,    /* Look for unread parameters.                  */
  877.         typeKeyword,            /* So we can see what type we missed, if any. */
  878.         &ignoredActualType,        /* What is would have been if not coerced.      */
  879.         (Ptr)&missedKeyword,    /* Data area.  (Keyword not handled.)          */
  880.         sizeof(missedKeyword),    /* Size of data area.                          */
  881.         &ignoredActualSize        /* Actual data size.                          */
  882.     );
  883.     /* No error means that we found some unused parameters. */
  884.     if (err == noErr) {
  885.         event.message = *(long *) &ignoredActualType;
  886.         event.where = *(Point *) &missedKeyword;
  887.         err = errAEEventNotHandled;
  888.     }
  889.     /* errAEDescNotFound means that there are no more parameters.  If we get
  890.        an error code other than that, flag it. */
  891.     return(err != errAEDescNotFound);
  892. }
  893.  
  894. pascal OSErr
  895. do_ae_open_application(AppleEvent *message, AppleEvent *reply, long refcon)
  896. {
  897. #pragma unused (message, refcon)
  898.     OSErr err;
  899.  
  900.     if (splash_dialog() == diSplashQuit) {
  901.         /* Set the global that lets the whole program exit. */
  902.         eventloopdone = TRUE;
  903.     }
  904.     AEPutParamPtr(reply, keyReplyErr, typeShortInteger, (Ptr) &err, sizeof(short));
  905.     return err;
  906. }
  907.  
  908. /* Called when we receive an AppleEvent with an ID of "kAEOpenDocuments".
  909.    This routine gets the direct parameter, parses it up into little FSSpecs,
  910.    and opens the first indicated file.  It also shows the technique to be used in
  911.    determining if you are doing everything the AppleEvent record is telling
  912.    you.  Parameters can be divided up into two groups: required and optional.
  913.    Before executing an event, you must make sure that you've read all the
  914.    required events.  This is done by making an "any more?" call to the
  915.    AppleEvent manager. */
  916.  
  917. pascal OSErr
  918. do_ae_open_documents(AppleEvent *message, AppleEvent *reply, long refcon)
  919. {
  920. #pragma unused (refcon)
  921.  
  922.     OSErr err;
  923. #if 0
  924.     gCurrentCursor = nil;
  925. #endif
  926.     OSErr        err2;
  927.     AEDesc        theDesc;
  928.     FSSpec        theFSS;
  929.     short        loop;
  930.     long        numFilesToOpen;
  931.     AEKeyword    ignoredKeyWord;
  932.     DescType    ignoredType;
  933.     Size        ignoredSize;
  934. /*    FileRecHndl    frHndl; */
  935.     WindowPtr    docWindow;
  936.  
  937.     theDesc.dataHandle = nil;
  938.         /* Make sure disposing of the descriptors is okay in all cases.
  939.         ** This will not be necessary after 7.0b3, since the calls that
  940.         ** attempt to create the descriptors will nil automatically
  941.         ** upon failure. */
  942.  
  943.     if (err = AEGetParamDesc(message, keyDirectObject, typeAEList, &theDesc))
  944.         return err;
  945.     if (!MissedAnyParameters(message)) {
  946.         /* Got all the parameters we need.  Now, go through the direct object,
  947.            see what type it is, and parse it up. */
  948.         if (!(err = AECountItems(&theDesc, &numFilesToOpen))) {
  949.             /* We have numFilesToOpen that need opening, as either a window
  950.                or to be printed.  Go to it... */
  951.             for (loop = 1; ((loop <= numFilesToOpen) && (!err)); ++loop) {
  952.                 err = AEGetNthPtr(        /* GET NEXT IN THE LIST...         */
  953.                     &theDesc,            /* List of file names.             */
  954.                     loop,                /* Item # in the list.             */
  955.                     typeFSS,            /* Item is of type FSSpec.         */
  956.                     &ignoredKeyWord,    /* Returned keyword -- we know.  */
  957.                     &ignoredType,        /* Returned type -- we know.     */
  958.                     (Ptr) &theFSS,        /* Where to put the FSSpec info. */
  959.                     sizeof(theFSS),        /* Size of the FSSpec info.         */
  960.                     &ignoredSize        /* Actual size -- we know.         */
  961.                 );
  962.                 if (err) break;
  963.                 if (open_game_from_fsspec(&theFSS)) break;
  964.             }
  965.         }
  966.     }
  967.     err2 = AEDisposeDesc(&theDesc);
  968.     err = (err ? err : err2);
  969.     AEPutParamPtr(reply, keyReplyErr, typeShortInteger, (Ptr) &err, sizeof(short));
  970.     return err;
  971. }
  972.  
  973. pascal OSErr
  974. do_ae_print_documents(AppleEvent *message, AppleEvent *reply, long refcon)
  975. {
  976.     OSErr err;
  977.  
  978.     AEPutParamPtr(reply, keyReplyErr, typeShortInteger, (Ptr) &err, sizeof(short));
  979.     return err;
  980. }
  981.  
  982. pascal OSErr
  983. do_ae_quit_application(AppleEvent *message, AppleEvent *reply, long refcon)
  984. {
  985.     OSErr err = noErr;
  986.  
  987.     /* Set the global that lets the whole program exit. */
  988.     eventloopdone = TRUE;
  989.     AEPutParamPtr(reply, keyReplyErr, typeShortInteger, (Ptr) &err, sizeof(short));
  990.     return noErr;
  991. }
  992.  
  993. /* A warning just gets displayed, no other action is taken. */
  994.  
  995. init_warning(str, a1, a2, a3, a4, a5, a6)
  996. char *str;
  997. long a1, a2, a3, a4, a5, a6;
  998. {
  999.     char buf[BUFSIZE], buf2[BUFSIZE];
  1000.  
  1001.     if (suppresswarnings) return;
  1002. #ifdef USE_CONSOLE
  1003.     fprintf(stderr, "Warning: ");
  1004.     fprintf(stderr, str, a1, a2, a3, a4, a5, a6);
  1005.     fprintf(stderr, "\n");
  1006.     fflush(stderr);
  1007. #endif
  1008.     /* Cursor may be weird from loading, reset it. */
  1009.     SetCursor(&qd.arrow);
  1010.     sprintf(buf, str, a1, a2, a3, a4, a5, a6);
  1011.     c2p(buf, buf2);
  1012.     ParamText(buf2, "\p", "\p", "\p");
  1013.     switch (CautionAlert(aInitWarning, nil)) {
  1014.         case 1:
  1015.             /* Just keep going, hope that warning was a false alarm. */
  1016.             if (0 /* option key or some such */) {
  1017.                 suppresswarnings = TRUE;
  1018.             }
  1019.             break;
  1020.         case 2:
  1021.             /* (should undo everything and blast back to initial choices) */
  1022.             ExitToShell();
  1023.             break;
  1024.     }
  1025. }
  1026.  
  1027. /* An init error is not necessarily fatal, but we still have to start over. */
  1028.  
  1029. init_error(str, a1, a2, a3, a4, a5, a6)
  1030. char *str;
  1031. long a1, a2, a3, a4, a5, a6;
  1032. {
  1033.     char buf[BUFSIZE], buf2[BUFSIZE];
  1034.  
  1035.     /* Make some space available, in case this is a memory exhaustion error. */
  1036.     if (spare != nil) {
  1037.         DisposHandle(spare);
  1038.         spare = nil;
  1039.     }
  1040. #ifdef USE_CONSOLE
  1041.     fprintf(stderr, "Error: ");
  1042.     fprintf(stderr, str, a1, a2, a3, a4, a5, a6);
  1043.     fprintf(stderr, "\n");
  1044.     fflush(stderr);
  1045. #endif
  1046.     /* Cursor may be weird from loading, reset it. */
  1047.     SetCursor(&qd.arrow);
  1048.     sprintf(buf, str, a1, a2, a3, a4, a5, a6);
  1049.     c2p(buf, buf2);
  1050.     ParamText(buf2, "\p", "\p", "\p");
  1051.     StopAlert(aInitError, nil);
  1052.     /* This is a bad time to die, no way to recover.  Fortunately,
  1053.        it's not a big loss, since there's no game yet to lose,
  1054.        and so we can just exit directly. */
  1055.     ExitToShell();
  1056. }
  1057.  
  1058. /* Runtime warnings are for when it's important to bug the players,
  1059.    but doesn't necessarily mean imminent danger of a crash. */
  1060.  
  1061. run_warning(str, a1, a2, a3, a4, a5, a6)
  1062. char *str;
  1063. long a1, a2, a3, a4, a5, a6;
  1064. {
  1065.     char buf[BUFSIZE], buf2[BUFSIZE];
  1066.  
  1067.     /* If we're not actually in the game yet, this is the same as an init warning. */
  1068.     if (beforestart) {
  1069.         init_warning(str, a1, a2, a3, a4, a5, a6);
  1070.         return;
  1071.     }
  1072.     if (suppresswarnings) return;
  1073. #ifdef USE_CONSOLE
  1074.     fprintf(stderr, "\nWarning: ");
  1075.     fprintf(stderr, str, a1, a2, a3, a4, a5, a6);
  1076.     fprintf(stderr, "\n");
  1077.     fflush(stderr);
  1078. #endif
  1079.     sprintf(buf, str, a1, a2, a3, a4, a5, a6);
  1080.     c2p(buf, buf2);
  1081.     ParamText(buf2, "\p", "\p", "\p");
  1082.     switch (CautionAlert(aRunWarning, nil)) {
  1083.         case 1:
  1084.             if (0 /* option key?? */) {
  1085.                 suppresswarnings = TRUE;
  1086.             }
  1087.             break;
  1088.         case 2:
  1089.             save_the_game(TRUE, TRUE);
  1090.             ExitToShell();
  1091.             break;
  1092.         case 3:
  1093.             /* Just blast out of here. */
  1094.             ExitToShell();
  1095.             break;
  1096.     }
  1097. }
  1098.  
  1099. /* An run error is fatal, but allow an emergency save, might be able to salvage. */
  1100.  
  1101. run_error(str, a1, a2, a3, a4, a5, a6)
  1102. char *str;
  1103. long a1, a2, a3, a4, a5, a6;
  1104. {
  1105.     char buf[BUFSIZE], buf2[BUFSIZE];
  1106.  
  1107.     /* If we're not actually in the game yet, this is the same as an init error. */
  1108.     if (beforestart) {
  1109.         init_error(str, a1, a2, a3, a4, a5, a6);
  1110.         return;
  1111.     }
  1112.     /* Make some space available, in case this is a memory exhaustion error. */
  1113.     if (spare != nil) {
  1114.         DisposHandle(spare);
  1115.         spare = nil;
  1116.     }
  1117. #ifdef USE_CONSOLE
  1118.     fprintf(stderr, "\nError: ");
  1119.     fprintf(stderr, str, a1, a2, a3, a4, a5, a6);
  1120.     fprintf(stderr, "\n");
  1121.     fflush(stderr);
  1122. #endif
  1123.     sprintf(buf, str, a1, a2, a3, a4, a5, a6);
  1124.     c2p(buf, buf2);
  1125.     ParamText(buf2, "\p", "\p", "\p");
  1126.     switch (StopAlert(aRunError, nil)) {
  1127.         case 1:
  1128.             break;
  1129.         case 2:
  1130.             save_the_game(TRUE, TRUE);
  1131.             break;
  1132.     }
  1133.     /* We're outta here - just ahead of scrambled heaps and dangling ptrs! */
  1134.     ExitToShell();
  1135. }
  1136.  
  1137. /* This is true when a side has a display that may be safely written to. */
  1138.  
  1139. active_display(side)
  1140. Side *side;
  1141. {
  1142.     return (side && side->ui && side->ui->active);
  1143. }
  1144.  
  1145. /* The Mac never has any display buffers to flush. */
  1146.  
  1147. flush_display_buffers() {}
  1148.  
  1149. record_real_start_time()
  1150. {
  1151.     time(&realstarttime);
  1152. }
  1153.  
  1154. /* Detect types of windows. */
  1155.  
  1156. is_da_window(win)
  1157. WindowPtr win;
  1158. {
  1159.     return (win != nil && ((WindowPeek) win)->windowKind < 0);
  1160. }
  1161.  
  1162. is_app_window(win)
  1163. WindowPtr win;
  1164. {
  1165.     return (win != nil && ((WindowPeek) win)->windowKind >= 0);
  1166. }
  1167.  
  1168. char *
  1169. newsfile_name()
  1170. {
  1171.     return "Xconq News"; /* get from resource */
  1172. }
  1173.  
  1174. char *
  1175. savefile_name()
  1176. {
  1177.     return "Saved Game"; /* get from resource */
  1178. }
  1179.  
  1180. FILE *
  1181. open_library_file(module)
  1182. Module *module;
  1183. {
  1184.     short curvrefnum;
  1185.     char fullnamebuf[255];
  1186.     FILE *fp = NULL;
  1187.     
  1188.     /* Can't open anonymous library modules. */
  1189.     if (module->name == NULL) return NULL;
  1190.     /* Generate library pathname. */
  1191.     make_pathname(xconqlib, module->name, "g", fullnamebuf);
  1192.     /* Now try to open the file. */
  1193.     if ((fp = fopen(fullnamebuf, "r")) != NULL) {
  1194.         /* Remember the filename where we found it. */
  1195.         module->filename = copy_string(fullnamebuf);
  1196.     } else {
  1197.         GetVol(NULL, &curvrefnum);
  1198.         SetVol(NULL, initialvrefnum);
  1199.         if ((fp = fopen(fullnamebuf, "r")) != NULL) {
  1200.             /* Remember the filename (what about volume?) where we found it. */
  1201.             module->filename = copy_string(fullnamebuf);
  1202.         }
  1203.         SetVol(NULL, curvrefnum);
  1204.     }
  1205.     return fp;
  1206. }
  1207.  
  1208. FILE *
  1209. open_explicit_file(module)
  1210. Module *module;
  1211. {
  1212.     short curvrefnum;
  1213.     char fullnamebuf[255];
  1214.     FILE *fp = NULL;
  1215.  
  1216.     if (module->filename == NULL) {
  1217.         if (module->name != NULL) {
  1218.             make_pathname(xconqlib, module->name, "g", fullnamebuf);
  1219.             if ((fp = fopen(fullnamebuf, "r")) != NULL) {
  1220.                 return fp;
  1221.             } else {
  1222.                 GetVol(NULL, &curvrefnum);
  1223.                 SetVol(NULL, initialvrefnum);
  1224.                 fp = fopen(fullnamebuf, "r");
  1225.                 SetVol(NULL, curvrefnum);
  1226.             }
  1227.         }
  1228.     } else {
  1229.         sprintf(fullnamebuf, "%s", module->filename);
  1230.         if ((fp = fopen(module->filename, "r")) != NULL) {
  1231.             return fp;
  1232.         }
  1233.         sprintf(fullnamebuf, ":%s", module->filename);
  1234.         if ((fp = fopen(fullnamebuf, "r")) != NULL) {
  1235.             return fp;
  1236.         }
  1237.         sprintf(fullnamebuf, "%s%s", ":lib:", module->filename);
  1238.         if ((fp = fopen(fullnamebuf, "r")) != NULL) {
  1239.             return fp;
  1240.         }
  1241.         /* Try opening a library module under where the program started. */
  1242.         GetVol(NULL, &curvrefnum);
  1243.         SetVol(NULL, initialvrefnum);
  1244.         fp = fopen(fullnamebuf, "r");
  1245.         SetVol(NULL, curvrefnum);
  1246.     }
  1247.     return fp;
  1248. }
  1249.  
  1250. make_pathname(path, name, extn, pathbuf)
  1251. char *path, *name, *extn, *pathbuf;
  1252. {
  1253.     sprintf(pathbuf, "");
  1254.     if (!empty_string(path)) {
  1255.     sprintf(pathbuf+strlen(pathbuf), "%s:", path);
  1256.     }
  1257.     sprintf(pathbuf+strlen(pathbuf), "%s", name);
  1258.     /* Don't add a second identical extension, but do add if extension
  1259.        is different (in case we want "foo.12" -> "foo.12.g" for instance) */
  1260.     if (strrchr(name, '.') && strcmp(strrchr(name, '.')+1, extn) == 0)
  1261.       return;
  1262.     if (!empty_string(extn)) {
  1263.     sprintf(pathbuf+strlen(pathbuf), ".%s", extn);
  1264.     }
  1265. }
  1266.  
  1267. /* Kernel callback to update info about the given side. */
  1268.  
  1269. update_side_display(side, side2, rightnow)
  1270. Side *side, *side2;
  1271. int rightnow;
  1272. {
  1273.     GrafPtr oldport;
  1274.     extern int mayseeall;
  1275.  
  1276.     if (active_display(side) && side2 != NULL) {
  1277.         GetPort(&oldport);
  1278.         if (gamewin != nil && ((WindowPeek) gamewin)->visible) {
  1279.             SetPort(gamewin);
  1280.             draw_side_status(side2);
  1281.         }
  1282.         /* (should do side closeups etc) */
  1283.         SetPort(oldport);
  1284.         if (side2 == dside && !side->ingame && side->status == 0 && wasingame) {
  1285.             /* (should be able to quit from here?) */
  1286.             CautionAlert(aOutOfGame, nil); 
  1287.             wasingame = FALSE;
  1288.             mayseeall = TRUE;
  1289.         }
  1290.     }
  1291. }
  1292.  
  1293. /* Kernel callback to show the current turn. */
  1294.  
  1295. update_turn_display(side, rightnow)
  1296. Side *side;
  1297. int rightnow;
  1298. {
  1299.     GrafPtr oldport;
  1300.     Map *map;
  1301.  
  1302.     if (active_display(side)) {
  1303.         c2p(absolute_date_string(curturn), curdatestr);
  1304.         GetPort(&oldport);
  1305.         if (gamewin != nil && ((WindowPeek) gamewin)->visible) {
  1306.             SetPort(gamewin);
  1307.             draw_game_date();
  1308.         }
  1309.         for_all_maps(map) {
  1310.             if (map->toph > 0) {
  1311.                 SetPort(map->window);
  1312.                 draw_top_line(map);
  1313.             }
  1314.         }
  1315.         SetPort(oldport);
  1316.     }
  1317. }
  1318.  
  1319. /* Callback that gets run once after all turn setup is done but before any movement. */
  1320.  
  1321. update_action_display(side, rightnow)
  1322. Side *side;
  1323. int rightnow;
  1324. {
  1325.     GrafPtr oldport;
  1326.     Map *map;
  1327.     UnitCloseup *unitcloseup;
  1328.  
  1329.     if (active_display(side)) {
  1330.         GetPort(&oldport);
  1331.         for_all_maps(map) {
  1332.             draw_selections(map);
  1333.             if (map->autoselect) {
  1334.                 unselect_all(map);
  1335.                 select_next_actor(map);
  1336.             }
  1337.         }
  1338.         for_all_unit_closeups(unitcloseup) {
  1339.             force_update(unitcloseup->window);
  1340.         }
  1341.         SetPort(oldport);
  1342.     }
  1343. }
  1344.  
  1345. update_action_result_display(side, unit, rslt, rightnow)
  1346. Side *side;
  1347. Unit *unit;
  1348. int rslt, rightnow;
  1349. {
  1350.     Action *action;
  1351.  
  1352.     if (active_display(side)) {
  1353.         DGprintf("%s %s result is %s\n",
  1354.                 unit_desig(unit),
  1355.                 action_desig((unit->act ? &(unit->act->nextaction) : NULL)),
  1356.                 hevtdefns[rslt].name);
  1357.         /* (should handle errors specially) */
  1358.         action = (unit->act ? &(unit->act->nextaction) : NULL);
  1359.         if (action == NULL) return;
  1360.         switch (action->type) {
  1361.             case A_CREATE_IN:
  1362.             case A_CREATE_AT:
  1363.             case A_BUILD:
  1364.                 if (rslt == A_ANY_DONE) {
  1365.                     update_construction_type_list();
  1366.                 }
  1367.                 break;
  1368.         }
  1369.     }
  1370. }
  1371.  
  1372. int toldoutcome = FALSE;
  1373.  
  1374. update_event_display(side, hevt)
  1375. Side *side;
  1376. HistEvent *hevt;
  1377. {
  1378.     Side *side2;
  1379.     extern int mayseeall;
  1380.  
  1381.     if (active_display(side)) {
  1382.         switch (hevt->type) {
  1383.           case H_SIDE_LOST:
  1384.             if (hevt->data[0] == side_number(side)) {
  1385.                 lost_game_dialog();
  1386.                 toldoutcome = TRUE;
  1387.                 mayseeall = TRUE;
  1388.             } else if ((side2 = side_n(hevt->data[0])) != NULL) {
  1389.                 /* Indicate that some other side lost. */
  1390.             }
  1391.               break;
  1392.           case H_SIDE_WON:
  1393.             if (hevt->data[0] == side_number(side)) {
  1394.                 won_game_dialog();
  1395.                 toldoutcome = TRUE;
  1396.                 mayseeall = TRUE;
  1397.             } else if ((side2 = side_n(hevt->data[0])) != NULL) {
  1398.                 /* Indicate that some other side won. */
  1399.             }
  1400.               break;
  1401.           case H_GAME_ENDED:
  1402.               if (!toldoutcome) game_over_dialog();
  1403.             mayseeall = TRUE;
  1404.             break;
  1405.           default:
  1406.               /* No special display. */
  1407.               break;
  1408.         }
  1409.         if (historywin != nil) {
  1410.             SetPort(historywin);
  1411.             calc_history_layout();
  1412.             force_update(historywin);
  1413.         }
  1414.     }
  1415. }
  1416.  
  1417. update_fire_at_display(side, unit, unit2, m, rightnow)
  1418. Side *side;
  1419. Unit *unit, *unit2;
  1420. int m, rightnow;
  1421. {
  1422.     int i, sx1, sy1, sw1, sh1, sx2, sy2, sw2, sh2, dx, dy, xx, yy;
  1423.     int startticks, innerticks;
  1424.     Map *map;
  1425.     GrafPtr oldport, curport = NULL;
  1426.  
  1427.     if (active_display(side)) {
  1428.         GetPort(&oldport);
  1429.         startticks = TickCount();
  1430.         i = 0;
  1431.         /* Tweak the pen modes of all the maps. */
  1432.         for_all_maps(map) {
  1433.             SetPort(map->window);
  1434.             PenMode(patXor);
  1435.             if (map->hw > 10) PenSize(2, 2);
  1436.             else PenSize(1, 1);
  1437.         }
  1438.         while (TickCount() < startticks + 32) {
  1439.             innerticks = TickCount();
  1440.             for_all_maps(map) {
  1441.                 if (curport != map->window) {
  1442.                     SetPort(map->window);
  1443.                     curport = map->window;
  1444.                 }
  1445.                 xform_unit(map, unit, &sx1, &sy1, &sw1, &sh1);
  1446.                 xform_unit(map, unit2, &sx2, &sy2, &sw2, &sh2);
  1447.                 /* Offset to draw lines from the middle of the units' images. */
  1448.                 sx1 += sw1 / 2;  sy1 += sh1 / 2;
  1449.                 sx2 += sw2 / 2;  sy2 += sh2 / 2;
  1450.                 /* Draw one segment of a line between the units. */
  1451.                 dx = (sx2 - sx1) / 4;  dy = (sy2 - sy1) / 4;
  1452.                 xx = sx1 + ((i / 2) % 4) * dx;  yy = sy1 + ((i / 2) % 4) * dy;
  1453.                 MoveTo(xx, yy);  Line(dx, dy);
  1454.             }
  1455.             while (TickCount() < innerticks + 1); /* 2 here seems a bit slowish */
  1456.             ++i;
  1457.         }
  1458.         /* Restore the pen modes of all the maps. */
  1459.         for_all_maps(map) {
  1460.             SetPort(map->window);
  1461.             PenNormal();
  1462.         }
  1463.         SetPort(oldport);
  1464.     }
  1465. }
  1466.  
  1467. /* Update any displayed info about the given unit. */
  1468.  
  1469. update_unit_display(side, unit, rightnow)
  1470. Side *side;
  1471. Unit *unit;
  1472. int rightnow;
  1473. {
  1474.     UnitCloseup *unitcloseup;
  1475.  
  1476.     if (active_display(side) && unit != NULL) {
  1477.         if (side != unit->side) update_unit_in_maps(unit);
  1478.         if (1 /* unit visible to side in any way */ && inside_area(unit->x, unit->y)) {
  1479.             update_cell_display(side, unit->x, unit->y, TRUE);
  1480.         }
  1481.         update_unit_in_lists(unit);
  1482.         if ((unitcloseup = find_unit_closeup(unit)) != NULL
  1483.             && 1 /* window is visible */) {
  1484.             draw_unit_closeup(unitcloseup);
  1485.         }
  1486.         if (unit->side != NULL && unit->act != NULL) {
  1487.             update_side_display(side, unit->side, rightnow);
  1488.         }
  1489.         if (constructionwin != nil
  1490.             && ((WindowPeek) constructionwin)->visible) {
  1491.             update_construction_unit_list(unit);
  1492.         }
  1493.     }
  1494. }
  1495.  
  1496. update_unit_in_maps(unit)
  1497. Unit *unit;
  1498. {
  1499.     int i;
  1500.     Map *map;
  1501.  
  1502.     if (side_controls_unit(dside, unit)) return;
  1503.     for_all_maps(map) {
  1504.         unselect_unit_on_map(map, unit);
  1505.     }
  1506. }
  1507.  
  1508. update_clock_display(side, rightnow)
  1509. Side *side;
  1510. int rightnow;
  1511. {
  1512.     GrafPtr oldport;
  1513.     Map *map;
  1514.     time_t now;
  1515.     extern time_t lastnow;
  1516.  
  1517.     if (active_display(side)) {
  1518.         time(&now);
  1519.         /* If no changes since the last draw, jump out of here. */
  1520.         if (now == lastnow) return;
  1521.         GetPort(&oldport);
  1522.         if (gamewin != nil && ((WindowPeek) gamewin)->visible) {
  1523.             SetPort(gamewin);
  1524.             draw_game_clocks();
  1525.         }
  1526. #if 0
  1527.         for_all_maps(map) {
  1528.             if (map->toph > 0) {
  1529.                 SetPort(map->window);
  1530.                 draw_top_line(map);
  1531.             }
  1532.         }
  1533. #endif
  1534.         SetPort(oldport);
  1535.     }
  1536. }
  1537.  
  1538. update_all_progress_displays(str, s)
  1539. char *str;
  1540. int s;
  1541. {
  1542.     GrafPtr oldport;
  1543.     extern char *gameprogressstr;
  1544.  
  1545.     if (!active_display(dside)) return;
  1546.     gameprogressstr = str;
  1547.     GetPort(&oldport);
  1548.     if (gamewin != nil && ((WindowPeek) gamewin)->visible) {
  1549.         SetPort(gamewin);
  1550.         draw_game_progress();
  1551.     }
  1552.     SetPort(oldport);
  1553. }
  1554.  
  1555. won_game_dialog()
  1556. {
  1557.     int done = FALSE;
  1558.     short ditem;
  1559.     WindowPtr win;
  1560.     short itemtype;  Handle itemhandle;  Rect itemrect;
  1561.  
  1562.     win = GetNewDialog(dWinGame, NULL, (DialogPtr) -1L);
  1563.     ShowWindow(win);
  1564.     while (!done) {
  1565.         draw_default_button(win, diWinGameQuit);
  1566.         ModalDialog(NULL, &ditem);
  1567.         switch (ditem) {
  1568.             case diWinGameQuit:
  1569.                 ExitToShell();
  1570.                 break;
  1571.             case diWinGameKeepGoing:
  1572.                 done = TRUE;
  1573.                 break;
  1574.             default:
  1575.                 break;
  1576.         }
  1577.     }
  1578.     DisposDialog(win);
  1579. }
  1580.  
  1581. lost_game_dialog()
  1582. {
  1583.     int done = FALSE;
  1584.     short ditem;
  1585.     WindowPtr win;
  1586.     short itemtype;  Handle itemhandle;  Rect itemrect;
  1587.  
  1588.     win = GetNewDialog(dLoseGame, NULL, (DialogPtr) -1L);
  1589.     ShowWindow(win);
  1590.     while (!done) {
  1591.         draw_default_button(win, diLoseGameQuit);
  1592.         ModalDialog(NULL, &ditem);
  1593.         switch (ditem) {
  1594.             case diLoseGameQuit:
  1595.                 ExitToShell();
  1596.                 break;
  1597.             case diLoseGameKeepGoing:
  1598.                 done = TRUE;
  1599.                 break;
  1600.             default:
  1601.                 break;
  1602.         }
  1603.     }
  1604.     DisposDialog(win);
  1605. }
  1606.  
  1607. game_over_dialog()
  1608. {
  1609.     int done = FALSE;
  1610.     short ditem;
  1611.     WindowPtr win;
  1612.     short itemtype;  Handle itemhandle;  Rect itemrect;
  1613.  
  1614.     win = GetNewDialog(dGameOver, NULL, (DialogPtr) -1L);
  1615.     ShowWindow(win);
  1616.     while (!done) {
  1617.         draw_default_button(win, diGameOverQuit);
  1618.         ModalDialog(NULL, &ditem);
  1619.         switch (ditem) {
  1620.             case diGameOverQuit:
  1621.                 ExitToShell();
  1622.                 break;
  1623.             case diGameOverKeepGoing:
  1624.                 done = TRUE;
  1625.                 break;
  1626.             default:
  1627.                 break;
  1628.         }
  1629.     }
  1630.     DisposDialog(win);
  1631. }
  1632.  
  1633. /* Move the window to a position staggered from the given last position. */
  1634.  
  1635. stagger_window(win, lasthp, lastvp)
  1636. WindowPtr win;
  1637. int *lasthp, *lastvp;
  1638. {
  1639.     int h, v;
  1640.     Rect winrect;
  1641.     GrafPtr oldport;
  1642.  
  1643.     if (*lasthp > 0) {
  1644.         h = *lasthp + 20;  v = *lastvp + 20;
  1645.         /* (should that no other window here, iterate stagger if so) */
  1646.         MoveWindow(win, h, v, FALSE);
  1647.         *lasthp = h;  *lastvp = v;
  1648.     } else {
  1649.         /* Don't move the first window, but do record its position. */
  1650.         GetPort(&oldport);
  1651.         SetPort(win);
  1652.         winrect = win->portRect;
  1653.         LocalToGlobal(&top_left(winrect));
  1654.         *lasthp = winrect.left;  *lastvp = winrect.top;
  1655.         SetPort(oldport);
  1656.     }
  1657. }
  1658.  
  1659. /* General routine to outline the given item of a given dialog. */
  1660.  
  1661. draw_default_button(dialog, ditem)
  1662. DialogPtr dialog;
  1663. short ditem;
  1664. {
  1665.     GrafPtr oldport;
  1666.     short itemtype;  Handle itemhandle;  Rect itemrect;
  1667.  
  1668.     GetPort(&oldport);
  1669.     SetPort(dialog);
  1670.     GetDItem(dialog, ditem, &itemtype, &itemhandle, &itemrect);
  1671.     PenSize(3, 3);
  1672.     InsetRect(&itemrect, -4, -4);
  1673.     FrameRoundRect(&itemrect, 16, 16);
  1674.     PenNormal();
  1675.     SetPort(oldport);
  1676. }
  1677.  
  1678. /* Cause an update of a window's entire contents. */
  1679.  
  1680. force_update(win)
  1681. WindowPtr win;
  1682. {
  1683.     GrafPtr oldport;
  1684.  
  1685.     if (win == nil) return;
  1686.     GetPort(&oldport);
  1687.     SetPort(win);
  1688.     EraseRect(&win->portRect);
  1689.     InvalRect(&win->portRect);
  1690.     SetPort(oldport);
  1691. }
  1692.  
  1693. force_overall_update()
  1694. {
  1695.     Map *map;
  1696.     List *list;
  1697.     UnitCloseup *unitcloseup;
  1698.  
  1699.     force_update(gamewin);
  1700.     force_update(historywin);
  1701.     force_update(constructionwin);
  1702.     force_update(helpwin);
  1703.     for_all_maps(map) {
  1704.         force_update(map->window);
  1705.     }
  1706.     for_all_lists(list) {
  1707.         force_update(list->window);
  1708.     }
  1709.     for_all_unit_closeups(unitcloseup) {
  1710.         force_update(unitcloseup->window);
  1711.     }
  1712. }
  1713.  
  1714. beep()
  1715. {
  1716.     SysBeep(20);
  1717. }
  1718.  
  1719. /* C-to-Pascal string conversion. */
  1720.  
  1721. c2p(register const char *s, register char *t)
  1722. {
  1723.     strcpy(t + 1, s);
  1724.     t[0] = strlen(s);
  1725. }
  1726.  
  1727. /* Shut a single game display. */
  1728.  
  1729. close_display(side)
  1730. Side *side;
  1731. {
  1732.     dside->ui->active = FALSE;
  1733.     /* And close some windows? */
  1734.     Dprintf("Mac display closed.\n");
  1735.     /* should attempt to release all memory. */
  1736. }
  1737.  
  1738. /* (should get name from a preference) */
  1739.  
  1740. char *
  1741. checkpoint_name()
  1742. {
  1743.     return "Checkpoint";
  1744. }
  1745.  
  1746. update_everything()
  1747. {
  1748.     if (active_display(dside)) {
  1749.         force_overall_update();
  1750.     }
  1751. }
  1752.  
  1753. setfiletype(char *name)
  1754. {
  1755. #ifdef THINK_C
  1756.     FileParam pb;
  1757.     Str255 tmpstr;
  1758.     
  1759.     c2p(name, tmpstr);
  1760.     pb.ioNamePtr = tmpstr;
  1761.     pb.ioVRefNum = 0;
  1762.     pb.ioFVersNum = 0;
  1763.     pb.ioFDirIndex = 0;
  1764.     if (PBGetFInfoSync(&pb) == noErr) {
  1765.         pb.ioFlFndrInfo.fdType = 'TEXT';
  1766.         pb.ioFlFndrInfo.fdCreator = 'XCNQ';
  1767.         PBSetFInfoSync(&pb);
  1768.     }
  1769. #endif
  1770. }
  1771.  
  1772. /* Returns true if we can connect to another game. */
  1773.  
  1774. can_connect()
  1775. {
  1776.     return TRUE;
  1777. }